import turbogears as tg
from turbogears import controllers, expose, flash, identity, redirect
from pyhweb import model as m
from turbogears.database import session
from cherrypy import request, response
from sqlalchemy import and_
import time, os
from pyrrd.rrd import RRD, RRA, DS
from pyrrd.graph import DEF, CDEF, VDEF
from pyrrd.graph import LINE, AREA, GPRINT
from pyrrd.graph import ColorAttributes, Graph
from twisted.internet import reactor, defer
from pyhweb import alert_sender
# from pyhweb import json
# import logging
# log = logging.getLogger("pyhweb.controllers")

stypes = ['GAUGE', 'COUNTER', 'DERIVE', 'AVERAGE']

asender = alert_sender.alertSender()

class Root(controllers.RootController):
    
    @expose(template="pyhweb.templates.node_list")
    @identity.require(identity.in_any_group(u"admin", u"user"))
    def index(self, srvid=0):
        server = [srvid, '']
        allnode = session.query(m.Node).all()
        if srvid != 0:
            nodes = m.Server.by_id(srvid).nodes
            server[1] = m.Server.by_id(srvid).name
        else:
            nodes = allnode
        return dict(allnode = allnode,
                    server = server,
                    nodes = nodes)

    @expose(content_type='image/png')
    def getImage(self, **kw):
        startTime = int(kw['startTime'])
        endTime = int(kw['endTime'])
        
        if kw['p_or_i'] == 'plug':
            plugin = session.query(m.Plugin).filter_by(plugin_id = \
                                                       kw['stuffid']).first()
            vtype = plugin.vtype
            label = '"' + plugin.title + '"'
            step = plugin.delay
            vals = {}
            for i in plugin.items:
                vals[i] = session.query(m.Value).filter(and_(\
                    m.Value.item_id == i.item_id, m.Value.timestamp >= \
                    startTime, m.Value.timestamp <= endTime)\
                        ).order_by(m.Value.timestamp).all()
        
        elif kw['p_or_i'] == 'item':
            item = m.Item.by_id(kw['stuffid'])
            label = '"' + item.label + '"'
            vtype = item.plugin.vtype
            vals = {}
            step = item.plugin.delay
            vals[item]= session.query(m.Value).filter(and_(m.Value.item_id ==\
                item.item_id, m.Value.timestamp >= startTime,\
                        m.Value.timestamp <= endTime)\
                    ).order_by(m.Value.timestamp).all()

        vals_by_time = {}
        for i in vals.keys():
            for j in vals[i]:
                vals_by_time[j.timestamp] = []
        for i in vals.keys():
            t = 0
            for j in vals[i]:
                """if vtype == 0:
                    if j.value_int not in vals_by_time[j.timestamp]:
                        vals_by_time[j.timestamp].append(j.value_int)
                else:
                    if j.value_flt not in vals_by_time[j.timestamp]:
                        vals_by_time[j.timestamp].append(j.value_flt)"""
                if vtype == 0:
                    if len(vals_by_time[j.timestamp]) < t:
                        vals_by_time[j.timestamp].append(0)
                    vals_by_time[j.timestamp].append(j.value_int)
                else:
                    if len(vals_by_time[j.timestamp]) < t:
                        vals_by_time[j.timestamp].append(0.0)
                    vals_by_time[j.timestamp].append(j.value_int)
            t += 1

        times = vals_by_time.keys()
        times.sort()
        
        dss = []
        dslist = []
        dsdict = {}
        itkeys = {}
        for i in vals.keys():
            name = i.name
            itkeys[i.name] = i
            stype = i.stype
            dslist.append(DS(ds_name = name, ds_type = stypes[stype], \
                             heartbeat = step*10))
            dsdict[i] = DS(ds_name = name, ds_type = stypes[stype], \
                           heartbeat = step*10)
        dss.extend(dslist)
        
        maxStep = int((endTime - startTime)/step)
        rras = []
        rra1 = RRA(cf='AVERAGE', xff=0.5, steps=1, rows=maxStep)
        rras.append(rra1)
        
        f = os.tmpnam()
        myRRD = RRD(f, ds=dss, rra=rras, start=startTime)
        myRRD.create()
                
        #fill the RRD:
        for i in times:
            myRRD.bufferValue(i, *tuple(vals_by_time[i]))
            myRRD.update()
        myRRD.update()
        #make the image:
        defs = []
        defdict = {}
        for i in dsdict.keys():
            defs.append(DEF(rrdfile=myRRD.filename, vname=i.label, \
                            ds_name=dsdict[i].name))
            defdict[i] = DEF(rrdfile=myRRD.filename, vname=i.label, \
                             ds_name=dsdict[i].name)
            
        ca = ColorAttributes()
        ca.back = '#333333'
        ca.canvas = '#333333'
        ca.shadea = '#000000'
        ca.shadeb = '#111111'
        ca.mgrid = '#CCCCCC'
        ca.axis = '#FFFFFF'
        ca.frame = '#AAAAAA'
        ca.font = '#FFFFFF'
        ca.arrow = '#FFFFFF'
        cols = ['#000000', '#FFFFFF', '#FF7F00', '#007FFF', '#7FFF00', \
                '#7F00FF', '#00FF7F', '#FF007F', '#FFFF00', '#00FFFF', \
                '#FF00FF', '#FF0000','#00FF00','#0000FF']
        areas = []
        lines = []
        cdefs = []
        vdefs = []
        its = itkeys.keys()
        its.sort()
        for i in its:
            d = itkeys[i]
            if str(d.draw) in ["LINE","LINE1"]:
                lines.append(LINE(1,def_obj=defdict[d], color = cols.pop(),
                                  legend = d.name))
            elif str(d.draw) == "LINE2":
                lines.append(LINE(2,def_obj=defdict[d], color = cols.pop(),
                                  legend = d.name))
            elif str(d.draw) == "LINE3":
                lines.append(LINE(3,def_obj=defdict[d], color = cols.pop(),
                                  legend = d.name))
            elif str(d.draw) == "STACK":
                areas.append(AREA(def_obj=defdict[d], stack = True,
                                  color = cols.pop(), legend = d.name))
            else:
                areas.append(AREA(def_obj=defdict[d], color = cols.pop(), \
                              legend=d.name))
            if d.cdef not in ["", None]:
                cdefs.append(CDEF(vname = d.name + "cdef", rpn = d.cdef))
        gf = 'pyhweb/static/images/' + identity.current.visit_key + '.png'
        g = Graph(gf, start = startTime, end = endTime, width=640, \
                  height=160, vertical_label = label)
        g.data.extend(defs + areas + lines + cdefs)
        g.write()
        os.remove(f)
        return '/'.join(gf.split('/')[1:])

    
    @expose()
    @identity.require(identity.in_group("admin"))
    def save_node(self, **kw):
        if int(kw["node_id"]) != 0:
            Node = m.Node.by_id(int(kw["node_id"]))
            Node.status = 2 if kw.has_key("status") else Node.status \
                if Node.status != 2 else 0
        else:
            Node = m.Node()
            Node.status = 1 if kw.has_key("status") else 0
        Node.name = kw["name"]
        Node.addr = kw["addr"]
        Node.port = int(kw["port"])
        Node.proto = int(kw["proto"])
        flash("Changes saved!")
        raise redirect("/")

    @expose()
    @identity.require(identity.in_group("admin"))
    def save_user(self, **kw):
        if int(kw["userid"]) != 0:
            User = m.User.by_id(kw["userid"])
            if kw["password"] != u'password':
                User.password = kw['password']
        else:
            User = m.User()
            User.password = kw['passowrd']
        User.user_name = kw['user_name']
        User.display_name = kw['display_name']
        User.email_address = kw['email_address']
        User.phone_num = kw['phone_num']
        for g in session.query(m.Group).all():
            if g.group_name in (kw["groups"]):
                if g not in User.groups:
                    User.groups.append(g)
            else:
                if g in User.groups:
                    User.groups.remove(g)
        flash("Changes saved!")
        raise redirect("/user_list")
    
    @expose()
    @identity.require(identity.in_group("admin"))
    def save_group(self, **kw):
        if int(kw["groupid"]) != 0:
            Group = m.Group.by_id(kw['groupid'])
        else:
            Group = m.Group()
        Group.group_name = kw["group_name"]
        Group.display_name = kw["display_name"]
        flash("Changes saved!")
        raise redirect("/group_list")
    
    @expose()
    @identity.require(identity.in_group("admin"))
    def add_node(self, **kw):
        server = m.Server.by_id(int(kw['srvid']))
        node   = m.Node.by_id(int(kw['node']))
        server.nodes.append(node)
        flash("Changes saved!")
        raise redirect("/index?srvid=" + str(kw['srvid']))
    
    @expose()
    @identity.require(identity.in_group("admin"))
    def add_parent(self, **kw):
        child  = m.Server.by_id(int(kw['childid']))
        parent = m.Server.by_id(int(kw['parent']))
        child.parents.append(parent)
        flash("Changes saved!")
        raise redirect("/server_list?childid=" + str(kw['childid']))
    
    @expose()
    @identity.require(identity.in_group("admin"))
    def add_child(self, **kw):
        parent = m.Server.by_id(int(kw['parentid']))
        child  = m.Server.by_id(int(kw['child']))
        parent.children.append(child)
        flash("Changes saved!")
        raise redirect("/server_list?parentid=" + str(kw['parentid']))
        
    @expose()
    @identity.require(identity.in_group("admin"))
    def save_action(self, **kw):
        if int(kw['action_id']) == 0:
            Action = m.Action()
        else:
            Action = m.Action.by_id(int(kw['action_id']))
        Action.method     = kw['method']
        Action.msg        = kw['msg']
        Action.event_type = kw['event_type']
        grp = m.Group.by_id(kw['group'])
        grp.actions.append(Action)
        flash("Action saved!")
        redirect("/action_list")
    
    @expose()
    @identity.require(identity.in_group("admin"))
    def save_plugin(self, **kw):
        if kw["plugid"] == 0:
            raise redirect("/error")
        Plugin = m.Plugin.by_id(kw["plugid"])
        Plugin.title = kw["title"]
        if int(Plugin.delay) != int(kw["delay"]):
            Plugin.delay = kw["delay"]
        Plugin.status = 1 if kw.has_key("status") else 0
        
        flash("Changes saved!")

        raise redirect("/plug_list?nodeid=" + kw["nodeid"])
    
    @expose()
    @identity.require(identity.in_group("admin"))
    def save_item(self, **kw):
        if kw["itemid"] == 0:
            raise redirect("/error")
        Item = m.Item.by_id(kw["itemid"])
        Item.stype = kw["stype"]
        Item.label = kw["label"]
        Item.cdef  = kw["cdef"]
        Item.draw  = kw["draw"]
        
        flash("Changes saved!")

        raise redirect("/items?plugid=" + str(Item.plugin.plugin_id))

    @expose()
    @identity.require(identity.in_group("admin"))
    def save_server(self, **kw):
        if int(kw["server_id"]) != 0:
            Server = m.Server.by_id(int(kw["server_id"]))
        else:
            Server = m.Server()
        Server.name = kw["name"]
        Server.addr = kw["addr"]
        Server.port = int(kw["port"])
        Server.alertport = int(kw["alertport"])
        Server.proto = int(kw["proto"])
        Server.status = 2 if kw.has_key("status") else Server.status\
              if Server.status in [0, 1] else 0
        flash("Changes saved!")
        raise redirect("/server_list")
    
    @expose()
    @identity.require(identity.in_group("admin"))
    def del_node(self, nodeid, srvid, submit):
        if nodeid != 0:
            if srvid not in [None, 0, '0']:
                print srvid
                srv = m.Server.by_id(srvid)
                node = m.Node.by_id(nodeid)
                srv.nodes.remove(node)
                flash("Node removed!")
                raise redirect("/index?srvid=" + str(srvid))
            else:
                node = m.Node.by_id(nodeid)
                session.delete(node)
                flash("Node deleted!")
                raise redirect("/")
    
    @expose()
    @identity.require(identity.in_group("admin"))
    def del_server(self, **kw):
        if int(kw['serverid']) != 0:
            if int(kw['childid']) != 0:
                child = m.Server.by_id(int(kw['childid']))
                parent = m.Server.by_id(int(kw['serverid']))
                child.parents.remove(parent)
                flash("Parent server removed!")
                raise redirect("/server_list?childid=" + str(kw['childid']))
            elif int(kw['parentid']) != 0:
                child = m.Server.by_id(int(kw['serverid']))
                parent = m.Server.by_id(int(kw['parentid']))
                child.parents.remove(parent)
                flash("Child server removed!")
                raise redirect("/server_list?parentid=" + str(kw['parentid']))
            else:
                srv = m.Server.by_id(int(kw['serverid']))
                session.delete(srv)
                flash("Server deleted!")
                raise redirect("/server_list")
    
    @expose()
    @identity.require(identity.in_group("admin"))
    def del_action(self, actionid=0, submit=""):
        if int(actionid) != 0:
            act = m.Action.by_id(int(actionid))
            session.delete(act)
            flash("Action deleted!")
            raise redirect("/action_list")

    @expose(template="pyhweb.templates.actions")
    @identity.require(identity.in_group("admin"))
    def action_list(self):
        allactions = session.query(m.Action).all()
        return dict(allactions = allactions)
    
    @expose(template="pyhweb.templates.action")
    @identity.require(identity.in_group("admin"))
    def action(self, actionid = 0, submit=""):
        if actionid != 0:
            action = m.Action.by_id(actionid)
        else:
            class a:
                def __init__(self):
                    self.action_id = 0
                    self.method = ""
                    self.group_id = 0
                    self.event_type = ""
                    self.msg = ""
            action = a()
        allgroups = session.query(m.Group).all()
        return dict(action = action, allgroups = allgroups)
    
    @expose(template="pyhweb.templates.node")
    @identity.require(identity.in_group("admin"))
    def node_opts(self, nodeid=0, submit=""):
        if nodeid != 0:
            node = session.query(m.Node).filter_by(node_id = nodeid).first()
            return dict(node = node)
        class n:
            def __init__(self, name):
                self.name    = name
                self.addr    = ""
                self.port    = 0
                self.proto   = 0
                self.status  = 0
                self.node_id = 0
        node=n("New node")
        return dict(node = node)
    
    @expose(template="pyhweb.templates.user")
    @identity.require(identity.in_group("admin"))
    def user_opts(self, userid=0, submit=""):
        groups = session.query(m.Group).all()
        if userid != 0:
            user = session.query(m.User).filter_by(user_id = userid).first()
        else:
            class u:
                def __init__(self, name):
                    self.user_name     = name
                    self.password      = ""
                    self.user_id       = 0
                    self.email_address = ""
                    self.phone_num  = ""
                    self.display_name  = ""
            user = u("newuser")
        return dict(user = user, groups = groups)

    @expose(template="pyhweb.templates.group")
    @identity.require(identity.in_group("admin"))
    def group_opts(self, groupid=0, submit=""):
        if groupid != 0:
            group = session.query(m.Group).filter_by(group_id =
                                                     groupid).first()
        else:
            class g:
                def __init__(self, name):
                    self.group_name     = name
                    self.group_id       = 0
                    self.display_name   = ""
            group = g("newgroup")
        return dict(group = group)
    
    @expose(template="pyhweb.templates.items")
    @identity.require(identity.in_group("admin"))
    def items(self, plugid, submit=""):
        plugin = session.query(m.Plugin).filter_by(plugin_id = plugid).first()
        return dict(plugin = plugin)
    
    @expose(template="pyhweb.templates.item")
    @identity.require(identity.in_group("admin"))
    def item(self, itemid, submit=""):
        item = session.query(m.Item).filter_by(item_id = itemid).first()
        return dict(item = item)
    
    @expose(template="pyhweb.templates.server")
    @identity.require(identity.in_group("admin"))
    def server_opts(self, serverid=0, submit=""):
        if serverid != 0:
            server = session.query(m.Server).filter_by(server_id = \
                                                       serverid).first()
            return dict(server = server)
        class s:
            def __init__(self, name):
                self.name = name
                self.addr = ""
                self.port = 0
                self.alertport = 0
                self.proto = 0
                self.status = 0
                self.key = ""
                self.server_id = 0
        server = s("New server")
        return dict(server = server)

    @expose(template="pyhweb.templates.plugin")
    @identity.require(identity.in_group("admin"))
    def plugin(self, nodeid=0, plugid=0, submit=""):
        plugin = session.query(m.Plugin).filter_by(plugin_id = plugid).first()
        return dict(plugin = plugin)

    @expose(template="pyhweb.templates.graph")
    @identity.require(identity.in_any_group("admin", "user"))
    def graph(self, **kw):
        if kw.has_key('plugid'):
            plugin = session.query(m.Plugin).filter_by(plugin_id = \
                                                       kw['plugid']).first()
            numeric = False if plugin.vtype == 2 else True
            return dict(plugin = plugin, numeric = numeric, item=None,\
                        t='plug')
        elif kw.has_key('itemid'):
            item = session.query(m.Item).filter_by(item_id = \
                                                   kw['itemid']).first()
            numeric = False if item.plugin.vtype == 2 else True
            return dict(plugin = None, numeric = numeric, item = item, \
                        t='item')

    @expose(template="pyhweb.templates.graphic")
    @identity.require(identity.in_any_group("admin", "user"))
    def graphic(self, **kw):
        if kw.has_key('plugid'):
            plugin = session.query(m.Plugin).filter_by(plugin_id = \
                                                       kw['plugid']).first()
            name = plugin.name
            p_or_i = 'plug'
            stuffid = kw['plugid']

        elif kw.has_key('itemid'):
            item = m.Item.by_id(kw['itemid'])
            name = item.name
            p_or_i = 'item'
            stuffid = kw['itemid']

        if kw.has_key('prev') or kw.has_key('next'):
            endTime = int(kw['endTime'])
            
        interv = None
        if kw.has_key('year'):
            if kw.has_key('prev'):
                endTime = endTime - (60*60*24*365)
            elif kw.has_key('next'):
                endTime = endTime + (60*60*24*365)
            else:
                endTime = int(time.time())
            startTime = endTime - (60*60*24*365)
            interv = 'year'
        elif kw.has_key('month'):
            if kw.has_key('prev'):
                endTime = endTime - (60*60*24*31)
            elif kw.has_key('next'):
                endTime = endTime + (60*60*24*31)
            else:
                endTime = int(time.time())
            startTime = endTime - (60*60*24*31)
            interv = 'month'
        elif kw.has_key('week'):
            if kw.has_key('prev'):
                endTime = endTime - (60*60*24*7)
            elif kw.has_key('next'):
                endTime = endTime + (60*60*24*7)
            else:
                endTime = int(time.time())
            startTime = endTime - (60*60*24*7)
            interv = 'week'
        elif kw.has_key('day'):
            if kw.has_key('prev'):
                endTime = endTime - (60*60*24)
            elif kw.has_key('next'):
                endTime = endTime + (60*60*24)
            else:
                endTime = int(time.time())
            startTime = endTime - (60*60*24)
            interv = 'day'
        elif kw.has_key('hour'):
            if kw.has_key('prev'):
                endTime = endTime - (60*60)
            elif kw.has_key('next'):
                endTime = endTime + (60*60)
            else:
                endTime = int(time.time())
            startTime = endTime - (60*60)
            interv = 'hour'
        else:
            startTime = time.mktime(time.strptime(kw['startTime'],\
                                                  "%Y.%m.%d %H:%M"))
            endTime = time.mktime(time.strptime(kw['endTime'],\
                                                "%Y.%m.%d %H:%M"))
            
        gr_img = self.getImage(stuffid = stuffid, startTime=startTime, \
                               endTime = endTime, p_or_i = p_or_i, name = name)

        return dict(image_file = gr_img,
                    name = name,
                    p_or_i = p_or_i,
                    stuffid = kw['plugid'],
                    endTime = endTime,
                    interv = interv)

    @expose(template="pyhweb.templates.tablic")
    @identity.require(identity.in_any_group("admin", "user"))
    def tablic(self, plugid=0, startTime=0, endTime=0, limit=100, submit=""):
        plugin= session.query(m.Plugin).filter_by(plugin_id = plugid).first()
        startTime = time.mktime(time.strptime(startTime,\
                                              "%Y.%m.%d %H:%M"))
        endTime = time.mktime(time.strptime(endTime,"%Y.%m.%d %H:%M"))
        items = []
        values = {}
        for i in plugin.items:
            items.append(i.name)
            vals = session.query(m.Value).\
                 filter_by(item_id = i.item_id).\
                 filter(m.Value.timestamp >= startTime).\
                 filter(m.Value.timestamp <= endTime).limit(int(limit)).all()
            for v in vals:
                try:
                    values[v.timestamp][i.name] = v.value_str
                except:
                    values[v.timestamp] = {}
                    values[v.timestamp][i.name] = v.value_str
        return dict(pluginname = plugin.name,
                    items = items,
                    values = values)

    @expose(template="pyhweb.templates.plug_list")
    @identity.require(identity.in_any_group("admin", "user"))
    def plug_list(self, nodeid=0, submit=""):
        if nodeid != 0:
            node = session.query(m.Node).filter_by(node_id = nodeid).first()
            return dict(node = node)

    @expose(template="pyhweb.templates.server_list")
    @identity.require(identity.in_any_group("admin", "user"))
    def server_list(self, parentid = 0, childid = 0):
        parent = [parentid,""]
        child = [childid, ""]
        allserver = session.query(m.Server).all()
        if parentid != 0:
            servers = m.Server.by_id(parentid).children
            parent[1] = m.Server.by_id(parentid).name
        elif childid != 0:
            servers = m.Server.by_id(childid).parents
            child[1] = m.Server.by_id(childid).name
        else:
            servers = allserver
        return dict(allserver = allserver,
                    parent = parent,
                    child = child,
                    servers = servers)

    @expose(template="pyhweb.templates.user_list")
    @identity.require(identity.in_group("admin"))
    def user_list(self):
        allusers = session.query(m.User).all()
        return dict(allusers = allusers)
    
    @expose(template="pyhweb.templates.group_list")
    @identity.require(identity.in_group("admin"))
    def group_list(self):
        allgroups = session.query(m.Group).all()
        return dict(allgroups = allgroups)

    @expose(template="pyhweb.templates.opts")
    @identity.require(identity.in_any_group("admin", "user"))
    def opts(self):
        return dict()

    @expose(template="pyhweb.templates.login")
    def login(self, forward_url=None, previous_url=None, *args, **kw):
        
        g = session.query(m.Group).filter(m.Group.group_name == \
                                          'admin').first() 
        if g == None:
            g = m.Group()
            g.group_name = 'admin'
            g.display_name = 'admin_group'
            
        if len(g.users) == 0:
            u = m.User()
            u.user_name = 'admin'
            u.password = 'changeme'
            g.users.append(u)
        
        if not identity.current.anonymous and identity.was_login_attempted() \
                and not identity.get_identity_errors():
            raise redirect(tg.url(forward_url or previous_url or '/', kw))

        forward_url = None
        previous_url = request.path

        if identity.was_login_attempted():
            msg = _("The credentials you supplied were not correct or "
                   "did not grant access to this resource.")
        elif identity.get_identity_errors():
            msg = _("You must provide your credentials before accessing "
                   "this resource.")
        else:
            msg = _("Please log in.")
            forward_url = request.headers.get("Referer", "/")

        response.status = 403
        return dict(message=msg, previous_url=previous_url, logging_in=True,
            original_parameters=request.params, forward_url=forward_url)

    @expose(template="pyhweb.templates.error")
    def error(self):
        return dict()

    @expose()
    def logout(self):
        try:
            os.remove('pyhweb/static/images/' + identity.current.visit_key + \
                      '.png')
        except:
            pass
        identity.current.logout()
        raise redirect("/")

